#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
/*
    管理服务端方法
    供客户端调用
*/

namespace rpc
{
    namespace server
    {
        /*参数类型*/
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT,
        };
        /*
            服务类
            --服务设置
            --参数校验
            --返回值校验
            --调用服务，返回结果
        */
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallback = std::function<void(const Json::Value &params, Json::Value& result)>; // 服务
            using ParamsDescribe = std::pair<std::string, VType>;

            ServiceDescribe(const std::string &mname, const ServiceCallback &cb,
                            std::vector<ParamsDescribe> &&desc, VType type) : _method_name(mname),
                                                                              _callback(cb),
                                                                              _params_desc(std::move(desc)),
                                                                              _return_type(type)
            {
            }
            const std::string &method() { return _method_name; }
            // 针对收到的请求中的参数进行校验
            bool paramCheck(const Json::Value &params)
            {
                // 1.校验是否存在此参数
                // 2.校验类型是否一致
                for (auto &desc : _params_desc)
                {
                    if (params.isMember(desc.first) == false)
                    {
                        LOG(ERROR, "参数字段完整性校验失败！%s 字段缺失！", desc.first.c_str());
                        return false;
                    }
                    if (check(desc.second, params[desc.first]) == false)
                    {
                        LOG(ERROR, "%s 参数类型校验失败！", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if (rtypeCheck(result) == false)
                {
                    LOG(ERROR, "回调处理函数中的响应信息校验失败！");
                    return false;
                }
                return true;
            }

        private:
            bool rtypeCheck(const Json::Value &result)
            {
                return check(_return_type, result);
            }
            bool check(VType type, Json::Value value)
            {
                switch (type)
                {
                case VType::BOOL:
                    return value.isBool();
                case VType::INTEGRAL:
                    return value.isIntegral();
                case VType::NUMERIC:
                    return value.isNumeric();
                case VType::STRING:
                    return value.isString();
                case VType::ARRAY:
                    return value.isArray();
                case VType::OBJECT:
                    return value.isObject();
                }
                return false;
            }
            std::string _method_name;                 // 方法名称
            ServiceCallback _callback;                // 实际的业务回调函数
            std::vector<ParamsDescribe> _params_desc; // 参数字段格式描述
            VType _return_type;                       // 结果作为返回值类型的描述
        };

        class SDescribeFactory
        {
        public:
            void setMethodName(const std::string &name)
            {
                _method_name = name;
            }
            void setReturnType(VType vtype)
            {
                _return_type = vtype;
            }
            void setParamsDesc(const std::string &pname, VType vtype)
            {
                _params_desc.push_back(ServiceDescribe::ParamsDescribe(pname, vtype));
            }
            void setCallback(const ServiceDescribe::ServiceCallback &cb)
            {
                _callback = cb;
            }
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(std::move(_method_name),
                                                         _callback,
                                                         std::move(_params_desc),
                                                         _return_type);
            }

        private:
            std::string _method_name;
            ServiceDescribe::ServiceCallback _callback;                // 实际的业务回调函数
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc; // 参数字段格式描述
            VType _return_type;                                        // 结果作为返回值类型的描述
        };

        /*
            管理ServiceDescribe
            增，删，查
        */
        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            void insert(const ServiceDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert({desc->method(), desc});
            }
            ServiceDescribe::ptr select(std::string method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(method_name);
                if (it == _services.end())
                    return ServiceDescribe::ptr();
                return it->second;
            }
            void move(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(method_name);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _services;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manager(std::make_shared<ServiceManager>()) {}
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                return _service_manager->insert(service);
            }
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                // 1.查找服务
                auto server = _service_manager->select(request->method());
                if (server.get() == nullptr)
                {
                    LOG(ERROR, "%s 服务未找到！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                // 2.参数校验
                if (false == server->paramCheck(request->params()))
                {
                    LOG(ERROR, "%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                // 3.调用服务
                Json::Value result;
                bool ret = server->call(request->params(), result);
                if (ret == false)
                {
                    LOG(ERROR, "%s 服务执行失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                // 4.返回结果
                return response(conn,request,result,RCode::RCODE_OK);
            }

        private:
            void response(const BaseConnection::ptr &conn, RpcRequest::ptr &req,
                          const Json::Value &res, RCode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setId(req->rid());
                msg->setMType(rpc::MType::RSP_RPC);
                msg->setRCode(rcode);
                msg->setResult(res);
                conn->send(msg);
            }
            ServiceManager::ptr _service_manager;
        };
    }
}